﻿using System.IO;
using UnityEditor;
using UnityEngine;


namespace AmazingAssets
{
    namespace CurvedWorldEditor
    {
        public class CurvedWorldBendSettingsTerrainDrawer : MaterialPropertyDrawer
        {
            private static class Label
            {
                public static string mainGroupName = "Curved World";

                public static string bendType = "Bend Type";
                public static string bendID = "Bend ID";
                public static string bendTransformNormal = "Transform Normal";
            }

            CurvedWorld.BEND_TYPE shaderSupportedBendType;
            int shaderSupportedBendID;

            CurvedWorld.BEND_TYPE updateBendType;
            int updateBendID;
            Material updateMaterial;


            void Init(string label)
            {
                CurvedWorld.BEND_TYPE[] bendTypes;
                int[] bendIDs;
                bool hasNormalTransform;

                if (EditorUtilities.StringToBendSettings(label, out bendTypes, out bendIDs, out hasNormalTransform))
                {
                    shaderSupportedBendType = bendTypes[0];
                    shaderSupportedBendID = bendIDs[0];
                }
            }


            public override void OnGUI(Rect position, MaterialProperty prop, GUIContent label, MaterialEditor editor)
            {
                Material material = (Material)editor.target;
                Init(prop.displayName);


                CurvedWorld.BEND_TYPE bendType;
                int bendID;
                bool normalTransform;

                EditorUtilities.GetBendSettingsFromVector(prop.vectorValue, out bendType, out bendID, out normalTransform);


                #region Bend Type               
                EditorGUI.BeginChangeCheck();
                using (new AmazingAssets.EditorGUIUtility.EditorGUILayoutBeginHorizontal())
                {
                    bendType = (CurvedWorld.BEND_TYPE)EditorGUILayout.Popup(" ", (int)bendType, EditorUtilities.bendTypesNamesForMenu);
                    EditorGUI.LabelField(GUILayoutUtility.GetLastRect(), "Bend Type", EditorUtilities.GetBendTypeNameInfo(bendType).forLable, EditorStyles.popup);

                    if (GUILayout.Button("≡", GUILayout.MaxWidth(20)))
                    {
                        GenericMenu menu = new GenericMenu();

                        menu.AddItem(new GUIContent("Find Controller"), false, EditorUtilities.CallbackFindController, (int)bendType + "_" + bendID);
                        menu.AddItem(new GUIContent("Editor Window"), false, EditorUtilities.CallbackOpenCurvedWorldSettingsWindow, (int)bendType + "_" + bendID);
                        menu.AddItem(new GUIContent("Curved World Keywords"), false, EditorUtilities.CallbackAnalyzeShaderCurvedWorldKeywords, material.shader);

                        menu.AddItem(new GUIContent("Reimport Shader"), false, EditorUtilities.CallbackReimportShader, material.shader);


                        menu.ShowAsContext();
                    }
                }

                bendID = EditorGUILayout.IntSlider("Bend ID", bendID, 1, EditorUtilities.MAX_SUPPORTED_BEND_IDS);
                if (EditorGUI.EndChangeCheck())
                {
                    prop.vectorValue = new Vector4((int)bendType, bendID, 0, 0);
                }


                if (bendType != shaderSupportedBendType || bendID != shaderSupportedBendID ||
                    File.Exists(EditorUtilities.GetBendFileLocation(bendType, bendID, EditorUtilities.EXTENSTION.cginc)) == false)
                {
                    EditorGUILayout.HelpBox("Missing Keywords!", MessageType.Error);

                    Rect helpBox = GUILayoutUtility.GetLastRect();

                    if (GUI.Button(new Rect(helpBox.xMax - 64 - 5, helpBox.yMin + 8, 64, 20), "Actions"))
                    {
                        updateBendType = bendType;
                        updateBendID = bendID;
                        updateMaterial = material;

                        GenericMenu menu = new GenericMenu();
                        menu.AddItem(new GUIContent("Update Shader"), false, CallBackUpdateShader);
                        menu.ShowAsContext();
                    }
                }
                #endregion
            }

            public override float GetPropertyHeight(MaterialProperty prop, string label, MaterialEditor editor)
            {
                return 0;
            }

            void CallBackUpdateShader()
            {
                string mainCGINCFilePath = EditorUtilities.GetGeneratedFilePath(updateBendType, updateBendID, EditorUtilities.EXTENSTION.cginc, false);
                if (File.Exists(mainCGINCFilePath) == false)
                {
                    EditorUtilities.CreateCGINCFile(updateBendType, updateBendID);

                    AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
                }


                string shaderPath = EditorUtilities.GetGeneratedTerrainShaderPath(updateBendType, updateBendID, false);
                if (File.Exists(shaderPath) == false)
                {
                    string sourceFolderPath = EditorUtilities.GetTempleTerrainFolderPath();
                    string desitnationFolderPath = EditorUtilities.GetGeneratedTerrainShadersFolderPath(updateBendType, updateBendID);


                    //https://stackoverflow.com/questions/58744/copy-the-entire-contents-of-a-directory-in-c-sharp

                    //Now Create all of the directories
                    string[] directories = Directory.GetDirectories(sourceFolderPath, "*", SearchOption.AllDirectories);
                    if (directories != null && directories.Length > 0)
                    {
                        foreach (string dirPath in directories)
                            Directory.CreateDirectory(dirPath.Replace(sourceFolderPath, desitnationFolderPath));
                    }
                    else
                    {
                        Directory.CreateDirectory(desitnationFolderPath);
                    }

                    //Copy all the files & Replaces any files with the same name
                    foreach (string newPath in Directory.GetFiles(sourceFolderPath, "*.*",
                        SearchOption.AllDirectories))
                        File.Copy(newPath, newPath.Replace(sourceFolderPath, desitnationFolderPath), true);



                    //Deleta all meta files
                    string[] allMetaFiles = Directory.GetFiles(desitnationFolderPath, "*.meta", SearchOption.AllDirectories);
                    foreach (string metaFile in allMetaFiles)
                    {
                        System.IO.File.Delete(metaFile);
                    }


                    //Read all files and make changes
                    string BEND_NAME_SMALL = EditorUtilities.GetBendTypeNameInfo(updateBendType).forLable;
                    string BEND_NAME_BIG = updateBendType.ToString().ToUpperInvariant();
                    string BEND_NAME_INDEX = ((int)updateBendType).ToString();
                    string ID = updateBendID.ToString();

                    string[] allShaderFiles = Directory.GetFiles(desitnationFolderPath, "*", SearchOption.AllDirectories);
                    foreach (string shaderFile in allShaderFiles)
                    {
                        string[] allLines = File.ReadAllLines(shaderFile);

                        for (int i = 0; i < allLines.Length; i++)
                        {
                            allLines[i] = allLines[i].Replace("#BEND_NAME_SMALL#", BEND_NAME_SMALL).
                                                      Replace("#ID#", ID).
                                                      Replace("#BEND_NAME_INDEX#", BEND_NAME_INDEX).
                                                      Replace("#BEND_NAME_BIG#", BEND_NAME_BIG);
                        }

                        File.WriteAllLines(shaderFile, allLines);
                    }

                    //Change .txt files extension to .shader
                    string[] allTxtFiles = Directory.GetFiles(desitnationFolderPath, "*.txt", SearchOption.AllDirectories);
                    foreach (string txtFile in allTxtFiles)
                    {
                        File.Move(txtFile, Path.ChangeExtension(txtFile, ".shader"));
                    }


                    AssetDatabase.Refresh();
                }

                updateMaterial.shader = (Shader)AssetDatabase.LoadAssetAtPath(shaderPath, typeof(Shader));
            }
        }
    }
}